package com.onlyxiahui.aware.run.common.advice;

import java.util.List;

import javax.validation.ConstraintViolationException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.support.WebExchangeBindException;
import org.springframework.web.server.ServerWebExchange;

import com.alibaba.fastjson.JSONException;
import com.onlyxiahui.aware.basic.work.business.error.ErrorCode;
import com.onlyxiahui.aware.basic.work.business.error.SystemError;
import com.onlyxiahui.aware.basic.work.business.exception.BusinessException;
import com.onlyxiahui.aware.basic.work.business.exception.SystemException;
import com.onlyxiahui.common.message.result.ResultMessage;
import com.onlyxiahui.framework.action.dispatcher.general.exception.MessageValidException;
import com.onlyxiahui.framework.json.validator.ValidatorResult;

/**
 * 全局业务异常处理 Description <br>
 * Date 2020-05-20 15:10:28<br>
 * 
 * @author XiaHui [onlovexiahui@qq.com]<br>
 * @since 1.0.0
 */
@ControllerAdvice
@Order(Ordered.LOWEST_PRECEDENCE)
public class CommonExceptionHanderAdvice {

	protected final Logger logger = LoggerFactory.getLogger(this.getClass());

	final static String DATA_TOO_LONG = "Data truncation: Data too long for column";
	final static String CANNOT_BE_NULL = "cannot be null";
	final static String NUMBER_FORMAT = "java.lang.NumberFormatException";

	/**
	 * 
	 * 
	 * 数据校验异常<br>
	 * Date 2020-11-12 11:07:36<br>
	 * 
	 * @param ex
	 * @param exchange
	 * @return
	 * @since 1.0.0
	 */
	@ResponseBody
	@ExceptionHandler(WebExchangeBindException.class)
	public Object handleWebExchangeBindException(WebExchangeBindException ex, ServerWebExchange exchange) {
		List<FieldError> fieldErrors = ex.getFieldErrors();
		ResultMessage m = new ResultMessage();
		if (null != fieldErrors) {
			for (FieldError fieldError : fieldErrors) {
				StringBuilder sb = new StringBuilder();
				sb.append("{");
				sb.append(fieldError.getField());
				sb.append("}");
				sb.append(fieldError.getDefaultMessage());

				m.addError(ErrorCode.validate.code("000"), sb.toString());
			}
			m.addWarning(ErrorCode.validate.code("000"), "数据验证不通过！");
		}
		Object body = exchange.getAttributes().get("requestBodyCache");
		String bodyText = (null == body) ? "" : body.toString();
		logger.error(bodyText, ex);
		return m;
	}

	@ResponseBody
	@ExceptionHandler(MethodArgumentNotValidException.class)
	public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, ServerWebExchange exchange) {
		List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
		ResultMessage m = new ResultMessage();
		if (null != fieldErrors) {
			for (FieldError fieldError : fieldErrors) {
				StringBuilder sb = new StringBuilder();
				sb.append("{");
				sb.append(fieldError.getField());
				sb.append("}");
				sb.append(fieldError.getDefaultMessage());

				m.addError(ErrorCode.validate.code("000"), sb.toString());
			}
			m.addWarning(ErrorCode.validate.code("000"), "数据验证不通过！");
		}
		Object body = exchange.getAttributes().get("requestBodyCache");
		String bodyText = (null == body) ? "" : body.toString();
		logger.error(bodyText, ex);
		return m;
	}

	@ResponseBody
	@ExceptionHandler(BindException.class)
	public Object handleBindException(BindException ex, ServerWebExchange exchange) {
		List<FieldError> fieldErrors = ex.getFieldErrors();
		ResultMessage m = new ResultMessage();
		if (null != fieldErrors) {
			for (FieldError fieldError : fieldErrors) {
				StringBuilder sb = new StringBuilder();
				sb.append("{");
				sb.append(fieldError.getField());
				sb.append("}");
				sb.append(fieldError.getDefaultMessage());

				m.addError(ErrorCode.validate.code("000"), sb.toString());
			}
			m.addWarning(ErrorCode.validate.code("000"), "数据验证不通过！");
		}
		Object body = exchange.getAttributes().get("requestBodyCache");
		String bodyText = (null == body) ? "" : body.toString();
		logger.error(bodyText, ex);
		return m;
	}

	@ResponseBody
	@ExceptionHandler(MessageValidException.class)
	public Object handleMessageValidException(MessageValidException ex, ServerWebExchange exchange) {
		List<ValidatorResult> errors = ex.getList();
		ResultMessage m = new ResultMessage();
		if (null != errors) {
			for (ValidatorResult vr : errors) {
				StringBuilder sb = new StringBuilder();
				sb.append("{");
				sb.append(vr.getPropertyPath());
				sb.append("}");
				sb.append(vr.getMessage());
				m.addError(vr.getErrorCode(), sb.toString());
			}
			m.addWarning(ErrorCode.validate.code("000"), "数据验证不通过！");
		}
		Object body = exchange.getAttributes().get("requestBodyCache");
		String bodyText = (null == body) ? "" : body.toString();
		logger.error(bodyText, ex);
		return m;
	}

	/**
	 * 
	 * 
	 * 全局异常<br>
	 * Date 2020-11-12 11:07:18<br>
	 * 
	 * @param ex
	 * @param exchange
	 * @return
	 * @since 1.0.0
	 */
	@ResponseBody
	@ExceptionHandler(Exception.class)
	public Object exception(Exception ex, ServerWebExchange exchange) {
		Object body = exchange.getAttributes().get("requestBodyCache");
		String bodyText = (null == body) ? "" : body.toString();
		logger.error(bodyText, ex);

		String message = (ex.getMessage());

		ResultMessage m = new ResultMessage();
		// 业务异常
		if (ex instanceof BusinessException) {
			BusinessException e = (BusinessException) ex;
			m.addError(e.getCode(), e.getMessage());
			m.addWarning(e.getCode(), null != e.getPrompt() ? e.getPrompt() : e.getMessage());
		} else if (ex instanceof SystemException) {
			SystemException e = (SystemException) ex;
			m.addError(e.getCode(), e.getMessage());
			m.addWarning(e.getCode(), null != e.getPrompt() ? e.getPrompt() : e.getMessage());
		} else if (ex instanceof DuplicateKeyException) {
			m.addError(SystemError.SYSTEM_EXCEPTIONS.value(), "插入重复数据！");
			m.addWarning(SystemError.SYSTEM_EXCEPTIONS.value(), "插入重复数据！");
		} else if (ex instanceof ConstraintViolationException) {
			m.addError(SystemError.PARAMETER_ERROR.value(), ex.getLocalizedMessage());
			m.addWarning(SystemError.PARAMETER_ERROR.value(), "数据验证不通过！");
		} else if (ex instanceof JSONException) {
			m.addError(SystemError.SYSTEM_EXCEPTIONS.value(), "参数输入的格式有误");
			m.addWarning(SystemError.SYSTEM_EXCEPTIONS.value(), "参数输入的格式有误");
		} else if (ex instanceof DataIntegrityViolationException) {
			message = ex.getCause().getMessage();
			if (message != null) {
				if (message.contains(DATA_TOO_LONG)) {
					message = message.replace(DATA_TOO_LONG, "").replace("at row 1", "").replace("'", "").trim();
					m.addError(SystemError.SYSTEM_EXCEPTIONS.value(), "参数" + message + "值长度已经超过有效值");
					m.addWarning(SystemError.SYSTEM_EXCEPTIONS.value(), "参数" + message + "值长度已经超过有效值");
				} else if (message.contains(CANNOT_BE_NULL)) {
					message = message.replace(CANNOT_BE_NULL, "").replace("Column", "").replace("'", "").trim();
					m.addError(SystemError.SYSTEM_EXCEPTIONS.value(), "参数" + message + "不能为空");
					m.addWarning(SystemError.SYSTEM_EXCEPTIONS.value(), "参数" + message + "不能为空");
				} else {
					m.addError(SystemError.SYSTEM_EXCEPTIONS.value(), ex.getMessage());
					m.addWarning(SystemError.SYSTEM_EXCEPTIONS.value(), "系统未知异常！");
				}
			}
		} else if ("com.onlyxiahui.common.dispatcher.exception.MessageValidException".equals(ex.getClass().getName())) {
			String data = ex.getMessage();
			m.addError(SystemError.PARAMETER_VALID_ERROR.value(), data);
			m.addWarning(SystemError.PARAMETER_VALID_ERROR.value(), "数据验证不通过！");
		} else {
			m.addError(SystemError.SYSTEM_EXCEPTIONS.value(), ex.getMessage());
			m.addWarning(SystemError.SYSTEM_EXCEPTIONS.value(), "系统未知异常！");
		}
		logger.error(message);
		return m;
	}
}
